package com.ywz.framework.security;

import com.ywz.framework.security.service.AccessDeniedHandlerImpl;
import com.ywz.framework.security.service.AuthenticationEntryPointImpl;
import com.ywz.framework.sso.SSOAuthenticationManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * 类描述 -> Spring Security 配置类
 *
 * @Author: ywz
 * @Date: 2024/09/27
 */
@Configuration
@EnableWebSecurity // 是开启SpringSecurity的默认行为
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级别的权限注解
public class SecurityConfig {
    @Value("${sso.enabled}")
    private boolean SSO_ENABLE = false;
    @Resource
    private AccessDeniedHandlerImpl accessDeniedHandler;
    @Resource
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    // 放行接口（登录、注册、获取验证码、忘记密码、下载图片）
    private static final String[] IGNORE_URI = {"/system/login", "/system/register", "/system/captcha", "/system/forgetPassword", "/image/download"};
    // swagger与静态资源放行
    private static final String[] SWAGGER_URIS = {"/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**", "/doc.html"};

    /**
     * 方法描述 -> 密码明文加密方式配置
     *
     * @Author: ywz
     * @Date: 2024/07/28
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 方法描述 -> 获取AuthenticationManager（认证管理器），登录时认证使用
     *
     * @param authenticationConfiguration 认证配置
     * @Author: ywz
     * @Date: 2024/07/28
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        if (SSO_ENABLE)
            return new SSOAuthenticationManager();
        return authenticationConfiguration.getAuthenticationManager();
    }


    /**
     * 方法描述 -> 获取SecurityFilterChain（过滤器链），配置过滤器
     *
     * @param http httpSecurity
     * @Author: ywz
     * @Date: 2024/07/28
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                // 基于 token，不需要 csrf
                .csrf().disable()
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                // 开启跨域以便前端调用接口
                .cors().and()
                .authorizeRequests()
                // 指定某些接口不需要通过验证即可访问。登录接口肯定是不需要认证的
                .antMatchers(IGNORE_URI).permitAll()
                // 静态资源，可匿名访问
                .antMatchers(SWAGGER_URIS).permitAll()
                // 这里意思是其它所有接口需要认证才能访问
                .anyRequest().authenticated()
                .and()
                // 添加JWT filter
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 基于 token，不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .build();
    }

}